#!/usr/bin/env python
# -*- mode: python; coding: utf-8; -*-
##--------------------------------------------------------------------------##
##
## Copyright (C) 1998-2003 Markus Oberhumer <markus@oberhumer.com>
## Copyright (C) 2003 Mt. Hood Playing Card Co.
## Copyright (C) 2005-2010 Skomoroh <skomoroh@users.sourceforge.net>
## Copyright (C) 2010-2013 Jeremy Austin-Bardo <tjaustinbardo@gmail.com>
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.
##
##- G02 -- S04 -------------------------------------------------------------##
__all__ = []


from .. import formlib as layout
from .. import pilelib as stack
from ..gamelib import info as gi, game
from ..packlib import info as cs

GT, SL = gi.GT, gi.SL
StackWrapper = stack.StackWrapper


class Foundation(stack.EmptyTalonBuildMethod, stack.SS_Foundation):
    """
    Build up in rank by same suit when _waste_ and _talon_ are gap.
    """
    pass


class Zodiac_RowStack(stack.NotFromRowStackBuildMethod, stack.UD_SS_RowStack):
    """
     Build either in rank by same suit from any but another _row_.
    """
    pass


class Zodiac_Reserve(stack.NotFromRowStackBuildMethod, stack.ReserveStack):
    """
    Build any card from any group but _row_.
    """
    pass


class TwelveSleepingMaids_Reserve(stack.OpenStack):
    """
    Flip W most pile of group top when _row_ gap.
    """

    def cardFlips(self):
        """
        cardFlips() -> bool

        Any _row_ gap turn W most top face up.

        :returns: card can be flipped?
        :rtype: boolean
        """
        if (not super(TwelveSleepingMaids_Reserve, self).cardFlips() or
            all(pile.cards for pile in self.game.s['rows'])):
            return False
        index = list(self.game.s['reserves']).index(self)
        return index == 0 or not self.game.s['reserves'][index - 1].cards


class Zodiac(game.Game):
    """
    Finish cards on _foundation_ without limit turns.

    _row_
      Pile 24 over 2 row N and S. Init deal 1 card. Build either in rank by
      same suit from any but _row_. Play top. Base none.

    _reserve_
      Pile 8 horz center. Init deal 1 card. Build 1 card from any but _row_.
      Play top.

    _talon_
      Pile 1 NW. Deal _waste_ 1 card.

    _waste_
      Pile 1 E of _talon_. Init deal 1 card. Build none. Play top.

    _foundation_
      Pile 8 over 2 rows N and S between _row_ and _reserve_. Build in rank
      by same suit, up N and down S, when _waste_ and _talon_ gap. Play top.

    seealso::
      <http://en.wikipedia.org/wiki/Zodiac_%28solitaire%29>
    ------
    :cvar Stack _talon_: stack.WasteTalon (max_rounds=INFINITE)
    :cvar Stack _waste_: stack.WasteStack
    :cvar Stack _foundations_: Foundation,
      Foundation (base_rank=KING, dir=-1)
    :cvar Stack _row_: Zodiac_RowStack (base_rank=GAP)
    :cvar Stack _reserve_: Zodiac_Reserve
    """
    __info__ = dict(id=467, name='Zodiac', game_type=GT.TWO_DECK, decks=2,
                    redeals=cs.INFINITE, skill_level=SL.BALANCED,
                    version='0.93fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _talon_ = StackWrapper(stack.WasteTalon, max_rounds=cs.INFINITE)
    _waste_ = stack.WasteStack
    _foundations_ = (Foundation,
                     StackWrapper(Foundation, base_rank=cs.KING, dir=-1),)
    _row_ = StackWrapper(Zodiac_RowStack, base_rank=cs.GAP)
    _reserve_ = Zodiac_Reserve

    def _create_game(self, rows=(12,) * 2, reserves=8, **kw):
        l, s = layout.Layout(self), self.s
        max_rows = max(max(rows), reserves)
        self.table_size = (l.XM + max_rows * l.XS, l.YM + 5 * l.YS,)
        center = lambda n: l.XM + ((max_rows - n) / 2) * l.XS
        y = l.YM
        for row in rows:  # Vert
            x = center(row)
            for i in range(row):  # Horz
                s['rows'].append(self._row_(x, y, game=self, offset=(0, 0)))
                x += l.XS
            y += 4 * l.YS
        dx, y = center(len(l.SUIT)), l.YM + l.YS
        for _foundation_ in self._foundations_:  # Vert
            x = dx
            for suit in l.SUIT:  # Horz
                s['foundations'].append(_foundation_(x, y, game=self, suit=suit))
                x += l.XS
            y += 2 * l.YS
        x, y = center(reserves), l.YM + 2 * l.YS
        for i in range(reserves):  # Horz
            s['reserves'].append(self._reserve_(x, y, game=self))
            x += l.XS
        x, y = l.XM + l.XS, l.YM + l.YS
        s['talon'] = self._talon_(x, y, game=self)
        l.set_ncards_text(s['talon'], 'sw')
        x += l.XS
        s['wastes'].append(self._waste_(x, y, game=self))
        l.set_ncards_text(s['wastes'][-1], 'se')
        l.defaultStackGroups()
        return l

    def _start(self, **kw):
        self._play_sound('deal')
        self.s['talon'].dealRow(rows=self.s['reserves'])
        self.s['talon'].dealRow()
        self.s['talon'].deal_cards()


class TwelveSleepingMaids(game.Game):
    """
    Finish cards on _foundation_ within 3 turns.

    _row_
      Pile 8 horz S _foundation_. Init deal 1 card. Build down in rank by same
      suit. Play seq.

    _reserve_
      Pile 12 horz N _foundation_. Init deal 4 close cards. Build none. Flip
      W top when _row_ gap.

    _talon_
      Pile 1 SE. Deal _waste_ 1 card.

    _waste_
      Pile 1 W of _talon_. Init deal 1 card. Build none. Play top.

    _foundation_
      Pile 8 horz. Build up in rank by same suit from base KING. Play top.
    ------
    :cvar Stack _talon_: stack.WasteTalon (max_rounds=3)
    :cvar Stack _waste_: stack.WasteStack
    :cvar Stack _foundation_: stack.SS_Foundation (base_rank=KING,
      mod=13)
    :cvar Stack _row_: stack.SS_RowStack
    :cvar Stack _reserve_: TwelveSleepingMaids_Reserve
    """
    __info__ = dict(id=722, name='Twelve Sleeping Maids',
                    game_type=GT.TWO_DECK, decks=2, redeals=2,
                    skill_level=SL.BALANCED, version='1.10fc')
    __author__ = 'Skomoroh'
    __version__ = 7.70

    _talon_ = StackWrapper(stack.WasteTalon, max_rounds=3)
    _waste_ = stack.WasteStack
    _foundation_ = StackWrapper(stack.SS_Foundation, base_rank=cs.KING,
                                mod=13)
    _row_ = stack.SS_RowStack
    _reserve_ = TwelveSleepingMaids_Reserve

    def _create_game(self, rows=8, reserves=12, playcards=8, **kw):
        l, s = layout.Layout(self), self.s
        max_rows = max(rows, reserves)
        dy = l._get_stack_height(3, l.YS)
        self.table_size = (l.XM + max_rows * l.XS,
                          l.YM + 2 * dy + l._get_stack_height(playcards, l.YS),)
        center = lambda n: l.XM + ((max_rows - n) / 2) * l.XS
        x, y = center(reserves), l.YM
        for i in range(reserves):  # Horz
            s['reserves'].append(self._reserve_(x, y, game=self,
                                             offset=(0, l.YOFFSET)))
            x += l.XS
        x = center(l.NSUITS)
        y += dy
        suits = l.SUITS
        suits.sort()  # suits together
        for i in suits:  # Horz
            s['foundations'].append(self._foundation_(x, y, game=self, suit=i))
            x += l.XS
        x = center(rows)
        y += dy
        for i in range(rows):  # Horz
            s['rows'].append(self._row_(x, y, game=self))
            x += l.XS
        x, y = self.width - l.XS, self.height - l.YS
        s['talon'] = self._talon_(x, y, game=self)
        l.set_ncards_text(s['talon'], 'n')
        l.set_rounds_text(s['talon'], 'nnn')
        x -= l.XS
        s['wastes'].append(self._waste_(x, y, game=self))
        l.set_ncards_text(s['wastes'][-1], 'n')
        l.defaultStackGroups()
        return l

    def _start(self, rows=5, **kw):
        for i in range(rows - 1):
            self.s['talon'].dealRow(rows=self.s['reserves'], flip=False, frames=0)
        self._play_sound('deal')
        self.s['talon'].dealRow()
        self.s['talon'].deal_cards()


PROVIDES = [Zodiac, TwelveSleepingMaids]